#ifndef PICCOLO_VK_DEVICE_H
#define PICCOLO_VK_DEVICE_H

#include "PiccoloVKCommon.h"

namespace Piccolo
{
    class PiccoloVKGraphicsContext;
    class PiccoloVKQueue;
    class PiccoloVKCommandPool;

    struct PiccoloVKSettings
    {
        VkFormat surfaceFormat = VK_FORMAT_B8G8R8A8_UNORM;
        VkFormat depthFormat = VK_FORMAT_D32_SFLOAT;
        VkPresentModeKHR presentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
        uint32_t swapchainImageCount = 3;
    };

    class PiccoloVKDevice
    {
    public:
        PiccoloVKDevice(PiccoloVKGraphicsContext* context, uint32_t graphicQueueCount, uint32_t presentQueueCount, const PiccoloVKSettings& settings = {});
        ~PiccoloVKDevice();

        VkDevice GetLogicDevice() const { return mDevice; }
        const PiccoloVKSettings& GetSettings() const { return mSettings; }

        PiccoloVKQueue* GetGraphicQueue(uint32_t index) const { return mGraphicQueues.size() < index + 1 ? nullptr : mGraphicQueues[index].get(); };
        PiccoloVKQueue* GetFirstGraphicQueue() const { return mGraphicQueues.empty() ? nullptr : mGraphicQueues[0].get(); };
        PiccoloVKQueue* GetPresentQueue(uint32_t index) const { return mPresentQueues.size() < index + 1 ? nullptr : mPresentQueues[index].get(); };
        PiccoloVKQueue* GetFirstPresentQueue() const { return mPresentQueues.empty() ? nullptr : mPresentQueues[0].get(); };
        VkPipelineCache GetPipelineCache() const { return mPipelineCache; }
        PiccoloVKCommandPool* GetDefaultCommandPool() const { return mDefaultCommandPool.get(); }

        uint32_t GetMemoryIndex(VkMemoryPropertyFlags memProps, uint32_t memTypeBits) const;

        VkCommandBuffer CreateAndBeginSingleCommandBuffer();
        void EndSingleCommandBuffer(VkCommandBuffer commandBuffer);

        VkResult CreateSimpleSampler(VkFilter filter, VkSamplerAddressMode addressMode, VkSampler* outSampler);

    private:
        void CreatePipelineCache();
        void CreateDefaultCommandPool();

        VkDevice mDevice = VK_NULL_HANDLE;
        PiccoloVKGraphicsContext* mContext = nullptr;

        std::vector<std::shared_ptr<PiccoloVKQueue>> mGraphicQueues;
        std::vector<std::shared_ptr<PiccoloVKQueue>> mPresentQueues;
        std::shared_ptr<PiccoloVKCommandPool> mDefaultCommandPool;

        PiccoloVKSettings mSettings;

        VkPipelineCache mPipelineCache = VK_NULL_HANDLE;
    };
}

#endif